#include "lfs2_port.h"
// #include "lfs.h"
#include "lfs2.h"
#include "print_rtt.h"
#include "spi_flash_op.h"

/* ---------- 用户可改区间 ---------- */
#define E_BASE_ADDR      FLASH_LFS2_START // 芯片内偏移，一般 0
#define E_TOTAL_SIZE     1280 * 1024      // 1.5 MB
#define E_BLOCK_SIZE     4096             // 4 KB 擦块
#define E_BLOCK_COUNT    320              // 320
#define E_CACHE_SIZE     256              // 文件系统缓存
#define E_LOOKAHEAD_SIZE 256              // 位图缓存
/* ---------- 以下别动 ---------- */

/* 内存池 ========================================================== */
__align(4) static uint8_t lfs2_read_buf[E_CACHE_SIZE];
__align(4) static uint8_t lfs2_prog_buf[E_CACHE_SIZE];
__align(4) static uint8_t lfs2_lookahead_buf[E_LOOKAHEAD_SIZE];
__align(4) static uint8_t lfs2_file_buf[E_CACHE_SIZE]; /* 文件缓存 */

int lfs2_block_read(const struct lfs2_config *c, lfs2_block_t block,
                    lfs2_off_t off, void *buffer, lfs2_size_t size)
{
  unsigned int address = E_BASE_ADDR + (E_BLOCK_SIZE * block) + off;
  SoftSPIFlash_Read(address, buffer, size);
  return LFS2_ERR_OK;
}
int lfs2_block_prog(const struct lfs2_config *c, lfs2_block_t block,
                    lfs2_off_t off, const void *buffer, lfs2_size_t size)
{
  unsigned int address = E_BASE_ADDR + (E_BLOCK_SIZE * block) + off;
  SoftSPIFlash_PageWrite(address, buffer, size);
  return LFS2_ERR_OK;
}
int lfs2_block_erase(const struct lfs2_config *c, lfs2_block_t block)
{
  unsigned int address = E_BASE_ADDR + (E_BLOCK_SIZE * block);
  SoftSPIFlash_SectorErase(address);
  return LFS2_ERR_OK;
}
int lfs2_block_sync(const struct lfs2_config *c)
{
  return LFS2_ERR_OK;
}
int clean_all_store_space(void)
{
  int i;
  for (i = 0; i < E_BLOCK_COUNT; i++)
  {
    SoftSPIFlash_SectorErase(E_BASE_ADDR + (E_BLOCK_SIZE * i));
  }
  return 0;
}
/* LittleFS 配置 ================================================== */
const struct lfs2_config p_lfs2_cfg = {
    /* 函数指针 */
    .read = lfs2_block_read,
    .prog = lfs2_block_prog,
    .erase = lfs2_block_erase,
    .sync = lfs2_block_sync,

    /* 块设备参数 */
    .read_size = E_CACHE_SIZE,
    .prog_size = E_CACHE_SIZE,
    .block_size = E_BLOCK_SIZE,
    .block_count = E_BLOCK_COUNT,
    .cache_size = E_CACHE_SIZE,
    .lookahead_size = E_LOOKAHEAD_SIZE,
    .block_cycles = 100, // 小缓存别用 500

    /* 静态缓存 */
    .read_buffer = lfs2_read_buf,
    .prog_buffer = lfs2_prog_buf,
    .lookahead_buffer = lfs2_lookahead_buf,
};

/* 文件配置（多开文件就再复制几份 e_file_bufX + e_file_cfgX） */
const struct lfs2_file_config p_lfs2_file_cfg = {
    .buffer = lfs2_file_buf,
    .attr_count = 0,
};

lfs2_t p_lfs2;
lfs2_file_t p_lfs2_file;
int lfs2_private_init(void)
{
  int err;
  struct lfs2_dir p_lfs2_dir;
  struct lfs2_info p_lfs2_info;
  err = lfs2_mount(&p_lfs2, &p_lfs2_cfg);
  if (err)
  {
    LOG_ERROR("mount e_lfs failed!\r\n");
    /**
         * @brief Construct a new clean all store space objectd
         *
         */
    clean_all_store_space();
    err = lfs2_format(&p_lfs2, &p_lfs2_cfg);
    if (err == 0)
    {
      LOG_INFO("format e_lfs sucess!\r\n");
    }
    else
    {
      LOG_ERROR("format e_lfs failed!\r\n");
      return -1;
    }
    err = lfs2_mount(&p_lfs2, &p_lfs2_cfg);
    if (err == 0)
    {
      LOG_INFO("mount e_lfs again sucess!\r\n");
    }
    else
    {
      LOG_ERROR("mount e_lfs again failed!\r\n");
      return -1;
    }
  }
  else
  {
    LOG_INFO("mount e_lfs sucess!\r\n");
  }
  err = lfs2_dir_open(&p_lfs2, &p_lfs2_dir, "/");
  if (err == 0)
  {
    LOG_INFO("open dir  sucess!\r\n");
  }
  else
  {
    LOG_ERROR("open dir failed!\r\n");
    return -1;
  }
  while (1)
  {
    err = lfs2_dir_read(&p_lfs2, &p_lfs2_dir, &p_lfs2_info);
    if (err == 0)
    {
      break;
    }
    LOG_INFO("%d: %s\n", p_lfs2_info.size, p_lfs2_info.name);
  }
  lfs2_dir_close(&p_lfs2, &p_lfs2_dir);
  return 0;
}
int lfs2_parameter_write(unsigned int address, const unsigned char *store_data, unsigned short size)
{
  int lfs_ret, write_size;
  lfs2_soff_t soff_t;
  int err;
  struct lfs2_dir p_lfs2_dir;
  struct lfs2_info p_lfs_info;

  // 使用读写+创建模式，但不截断文件
  lfs_ret = lfs2_file_opencfg(&p_lfs2, &p_lfs2_file, "paramenter",
                              LFS2_O_RDWR | LFS2_O_CREAT,
                              &p_lfs2_file_cfg);
  if (lfs_ret != 0)
  {
    LOG_ERROR("open save_data failed! error: %d\r\n", lfs_ret);
    return -1;
  }
  soff_t = lfs2_file_seek(&p_lfs2, &p_lfs2_file, address, LFS2_SEEK_SET);
  if (soff_t < 0)
  {
    LOG_ERROR("seek failed! error: %ld\r\n", soff_t);
    lfs2_file_close(&p_lfs2, &p_lfs2_file);
    return -2;
  }

  write_size = lfs2_file_write(&p_lfs2, &p_lfs2_file, store_data, size);
  if (write_size < 0)
  {
    LOG_ERROR("write failed! error: %d\r\n", write_size);
    lfs2_file_close(&p_lfs2, &p_lfs2_file);
    return -3;
  }
  // 同步文件系统以确保数据写入Flash
  err = lfs2_file_sync(&p_lfs2, &p_lfs2_file);
  if (err != 0)
  {
    LOG_ERROR("fs sync failed! error: %d\r\n", err);
    return -4;
  }
  lfs_ret = lfs2_file_close(&p_lfs2, &p_lfs2_file);
  if (lfs_ret != 0)
  {
    LOG_ERROR("close failed! error: %d\r\n", lfs_ret);
    return -5;
  }

  LOG_INFO("Write successful: %d bytes at address %u\r\n", write_size, address);

  // 等待一段时间让文件系统更新
  // 或者重新挂载文件系统以确保目录信息是最新的

  // 重新挂载文件系统以确保目录信息是最新的
  lfs2_unmount(&p_lfs2);
  err = lfs2_mount(&p_lfs2, &p_lfs2_cfg);

  if (err != 0)
  {
    LOG_ERROR("Remount failed! error: %d\r\n", err);
    return -1;
  }
  // 列出目录内容
  err = lfs2_dir_open(&p_lfs2, &p_lfs2_dir, "/");
  if (err != 0)
  {
    LOG_ERROR("Failed to open directory! error: %d\r\n", err);
    return -2;
  }

  while (1)
  {
    err = lfs2_dir_read(&p_lfs2, &p_lfs2_dir, &p_lfs_info);
    if (err <= 0)
    {
      break;
    }
    LOG_INFO("%d: %s\n", p_lfs_info.size, p_lfs_info.name);
  }
  lfs2_dir_close(&p_lfs2, &p_lfs2_dir);

  return write_size;
}
int lfs2_parameter_read(unsigned int address, unsigned char *store_data, unsigned short size)
{
  int lfs_ret, read_size;
  lfs2_soff_t soff_t;

  // 使用只读模式打开文件
  lfs_ret = lfs2_file_opencfg(&p_lfs2, &p_lfs2_file, "paramenter",
                              LFS2_O_RDWR | LFS2_O_CREAT,
                              &p_lfs2_file_cfg);
  if (lfs_ret != 0)
  {
    LOG_ERROR("open save_data failed! error: %d\r\n", lfs_ret);
    return -1;
  }

  soff_t = lfs2_file_seek(&p_lfs2, &p_lfs2_file, address, LFS2_SEEK_SET);
  if (soff_t < 0)
  {
    LOG_ERROR("seek failed! error: %ld\r\n", soff_t);
    lfs2_file_close(&p_lfs2, &p_lfs2_file);
    return -1;
  }

  read_size = lfs2_file_read(&p_lfs2, &p_lfs2_file, store_data, size);
  if (read_size < 0)
  {
    LOG_ERROR("read failed! error: %d\r\n", read_size);
    lfs2_file_close(&p_lfs2, &p_lfs2_file);
    return -1;
  }

  lfs_ret = lfs2_file_close(&p_lfs2, &p_lfs2_file);
  if (lfs_ret != 0)
  {
    LOG_ERROR("close failed! error: %d\r\n", lfs_ret);
    return -1;
  }
  LOG_INFO("Read successful: %d bytes from address %u\r\n", read_size, address);
  return read_size;
}
#if LFS_TEST
uint8_t write_data[32];
uint8_t read_saved_data[32];
int two_file_test(void)
{
  volatile int ret, i, size, read_size;
  uint32_t address = 0;
  read_size = lfs2_parameter_read(address, read_saved_data, 32);
  LOG_INFO("parameter read address: 0x%08X,write size:%d\r\n", address, read_size);
  LOG_BYTE(read_saved_data, read_size);
  memset(write_data, 0x00, 32);
  size = lfs2_parameter_write(address, write_data, 32);
  LOG_INFO("parameter write address: 0x%08X,write size:%d\r\n", address, size);
  read_size = lfs2_parameter_read(address, read_saved_data, 32);
  LOG_INFO("parameter read address: 0x%08X,write size:%d\r\n", address, read_size);
  LOG_BYTE(read_saved_data, read_size);

  memset(write_data, 0x01, 32);
  size = lfs2_parameter_write(address, write_data, 32);
  LOG_INFO("parameter write address: 0x%08X,write size:%d\r\n", address, size);

  memset(write_data, 0x02, 32);
  size = lfs2_parameter_write(address, write_data, 32);
  LOG_INFO("e2prom write address: 0x%08X,write size:%d\r\n", address, size);
  read_size = lfs2_parameter_read(address, read_saved_data, 32);
  LOG_INFO("e2prom read address: 0x%08X,write size:%d\r\n", address, read_size);
  LOG_BYTE(read_saved_data, read_size);

  read_size = lfs2_parameter_read(address, read_saved_data, 32);
  LOG_INFO("parameter read address: 0x%08X,write size:%d\r\n", address, read_size);
  LOG_BYTE(read_saved_data, read_size);

  read_size = lfs2_parameter_read(address, read_saved_data, 32);
  LOG_INFO("parameter read address: 0x%08X,write size:%d\r\n", address, read_size);
  LOG_BYTE(read_saved_data, read_size);

  read_size = lfs2_parameter_read(address, read_saved_data, 32);
  LOG_INFO("e2prom read address: 0x%08X,write size:%d\r\n", address, read_size);
  LOG_BYTE(read_saved_data, read_size);
  return 1;
}
#endif
